package com.yvon.maple.service.msg.core.support.action;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Throwables;
import com.yvon.boot.common.result.ResponseData;
import com.yvon.boot.common.result.ResultCode;
import com.yvon.maple.service.msg.core.model.entity.MessageTemplate;
import com.yvon.maple.service.msg.core.common.enums.MessageType;
import com.yvon.maple.service.msg.core.common.enums.IdType;
import com.yvon.maple.service.msg.core.mapper.MessageTemplateMapper;
import com.yvon.maple.service.msg.core.common.enums.ChannelType;
import com.yvon.maple.service.msg.core.common.enums.TemplateType;
import com.yvon.maple.service.msg.core.common.utils.ContentHolderUtil;
import com.yvon.maple.service.msg.core.common.utils.TaskInfoUtils;
import com.yvon.maple.service.msg.core.model.vo.MessageVo;
import com.yvon.maple.service.msg.core.common.domain.TaskInfo;
import com.yvon.maple.service.msg.core.common.model.content.ContentModel;
import com.yvon.maple.service.msg.core.common.model.send.SendTaskModel;
import com.yvon.maple.service.msg.core.support.pipeline.BusinessProcess;
import com.yvon.maple.service.msg.core.support.pipeline.ProcessContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 拼装参数
 *
 * @author : Yvon
 * @since : 2021-12-22
 */
@Slf4j
@Service
public class AssembleAction implements BusinessProcess {

    @Autowired
    private MessageTemplateMapper messageTemplateMapper;

    @Override
    public void process(ProcessContext context) {
        SendTaskModel sendTaskModel = (SendTaskModel) context.getProcessModel();
        Long messageTemplateId = sendTaskModel.getMessageTemplateId();

        try {
        MessageTemplate messageTemplate = messageTemplateMapper.selectById(messageTemplateId);
        if (Objects.isNull(messageTemplate) || 0 == messageTemplate.getStatus()) {
            context.setNeedBreak(true).setResponse(ResponseData.failed(ResultCode.TEMPLATE_NOT_FOUND));
            return;
        }

        List<TaskInfo> taskInfos = assembleTaskInfo(sendTaskModel, messageTemplate);
        sendTaskModel.setTaskInfo(taskInfos);
        } catch (Exception e) {
            context.setNeedBreak(true).setResponse(ResponseData.failed(ResultCode.SERVICE_ERROR));
            log.error("assemble task fail! templateId:{}, e:{}", messageTemplateId, Throwables.getStackTraceAsString(e));
        }
    }

    /**
     * 组装任务信息
     *
     * @param sendTaskModel   发送任务模型
     * @param messageTemplate 消息模板
     * @return List<TaskInfo>
     * @author : Yvon / 2021-12-22
     */
    private List<TaskInfo> assembleTaskInfo(SendTaskModel sendTaskModel, MessageTemplate messageTemplate) {
        List<MessageVo> messageVoList = sendTaskModel.getMessageVoList();
        List<TaskInfo> taskInfoList = new ArrayList<>();

        for (MessageVo messageVo : messageVoList) {
            TaskInfo taskInfo = TaskInfo.builder()
                    .messageTemplateId(messageTemplate.getId())
                    .businessId(TaskInfoUtils.generateBusinessId(messageTemplate.getId(), messageTemplate.getTemplateType()))
                    .receiver(messageVo.getReceiver())
                    .idType(IdType.getEnumByCodeEn(messageTemplate.getIdType()))
                    .channelType(ChannelType.getEnumByCodeEn(messageTemplate.getChannelType()))
                    .templateType(TemplateType.getEnumByCodeEn(messageTemplate.getTemplateType()))
                    .messageType(MessageType.getEnumByCodeEn(messageTemplate.getMessageType()))
                    .sendAccount(messageTemplate.getSendAccount())
                    .contentModel(getContentModelValue(messageTemplate, messageVo))
                    .deduplicationTime(messageTemplate.getDeduplicationTime())
                    .nightShield(messageTemplate.getNightShield()).build();
            taskInfoList.add(taskInfo);
        }
        return taskInfoList;
    }

    /**
     * 获取 contentModel，替换模板msgContent中占位符信息
     */
    private static ContentModel getContentModelValue(MessageTemplate messageTemplate, MessageVo messageVo) {

        // 得到真正的ContentModel 类型
        Class contentModelClass = ChannelType.getChanelModelClassByCodeEn(messageTemplate.getChannelType());


        // 得到模板的 msgContent 和 入参
        Map<String, String> variables = messageVo.getVariables();
        String json = toJsonString(messageTemplate.getMsgContent());
        JSONObject jsonObject = JSON.parseObject(json);


        // 通过反射 组装出 contentModel
        Field[] fields = ReflectUtil.getFields(contentModelClass);
        ContentModel contentModel = (ContentModel) ReflectUtil.newInstance(contentModelClass);
        for (Field field : fields) {
            String originValue = jsonObject.getString(field.getName());
            if (StrUtil.isNotBlank(originValue)) {
                originValue = originValue.replace('”','"');
                String resultValue = ContentHolderUtil.replacePlaceHolder(originValue, variables);
                Object resultObj = JSONUtil.isJsonObj(resultValue) ? JSONUtil.toBean(resultValue, field.getType()) : resultValue;
                ReflectUtil.setFieldValue(contentModel, field, resultObj);
            }
        }

        return contentModel;
    }

    private static String toJsonString(String s) {
        char[] tempArr = s.toCharArray();
        int tempLength = tempArr.length;
        for (int i = 0; i < tempLength; i++) {
            if (tempArr[i] == ':' && tempArr[i + 1] == '"') {
                for (int j = i + 2; j < tempLength; j++) {
                    if (tempArr[j] == '"') {
                        if (tempArr[j + 1] != ',' && tempArr[j + 1] != '}') {
                            // 将value中的 双引号替换为中文双引号
                            tempArr[j] = '”';
                        } else if (tempArr[j + 1] == ',' || tempArr[j + 1] == '}') {
                            break;
                        }
                    }
                }
            }
        }
        return new String(tempArr);
    }

}
